package com.ds.esd.bpm.custom.plugins.right;

import com.alibaba.fastjson.annotation.JSONField;
import com.ds.bpm.client.ActivityDef;
import com.ds.bpm.client.ActivityDefRight;
import com.ds.bpm.client.RouteToType;
import com.ds.bpm.engine.WorkflowClientService;
import com.ds.bpm.enums.right.PerformGroupEnums;
import com.ds.config.TreeListResultModel;
import com.ds.esd.custom.annotation.TreeViewAnnotation;
import com.ds.esd.custom.api.annotation.APIEventAnnotation;
import com.ds.esd.custom.module.annotation.ModuleAnnotation;
import com.ds.esd.custom.nav.tab.buttonviews.NavButtonViewsViewAnnotation;
import com.ds.esd.dsm.domain.annotation.BpmDomain;
import com.ds.esd.dsm.domain.enums.BpmDomainType;
import com.ds.esd.util.TabPageUtil;
import com.ds.jds.core.esb.EsbUtil;
import com.ds.org.Org;
import com.ds.org.OrgNotFoundException;
import com.ds.org.Person;
import com.ds.server.OrgManagerFactory;
import com.ds.web.annotation.Aggregation;
import com.ds.web.annotation.AggregationType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.*;

@Controller
@RequestMapping("/bpm/plugins/select/")
@BpmDomain(type = BpmDomainType.right)
@Aggregation(type = AggregationType.customDomain, sourceClass = PerformTreeService.class)
public class PerformTreeService {

    @NavButtonViewsViewAnnotation()
    @ModuleAnnotation(dynLoad = true)
    @APIEventAnnotation
    @RequestMapping(method = RequestMethod.POST, value = "performSelect")
    @ResponseBody
    public TreeListResultModel<List<MultiActivityTree>> performSelect(String activityInstId, String nextActivityDefId, RouteToType action) {
        TreeListResultModel<List<MultiActivityTree>> performTree = new TreeListResultModel<>();
        performTree = TabPageUtil.getTabList(Arrays.asList(PerformGroupEnums.values()), MultiActivityTree.class);

        return performTree;

    }


    @TreeViewAnnotation
    @ModuleAnnotation(dynLoad = true)
    @APIEventAnnotation
    @RequestMapping(method = RequestMethod.POST, value = "Readers")
    @ResponseBody
    public TreeListResultModel<List<PerformOrgTree>> getReaders(String activityInstId, String nextActivityDefId, PerformGroupEnums performGroup, String topOrgId) {
        return getOrgTree(activityInstId, nextActivityDefId, performGroup, topOrgId);
    }

    @TreeViewAnnotation
    @ModuleAnnotation(dynLoad = true)
    @APIEventAnnotation
    @RequestMapping(method = RequestMethod.POST, value = "Performs")
    @ResponseBody
    public TreeListResultModel<List<PerformOrgTree>> getPerforms(String activityInstId, String nextActivityDefId, PerformGroupEnums performGroup, String topOrgId) {
        return getOrgTree(activityInstId, nextActivityDefId, performGroup, topOrgId);
    }

    @TreeViewAnnotation
    @ModuleAnnotation(dynLoad = true)
    @APIEventAnnotation
    @RequestMapping(method = RequestMethod.POST, value = "InsteadSigns")
    @ResponseBody
    public TreeListResultModel<List<PerformOrgTree>> getInsteadSignsTree(String activityInstId, String nextActivityDefId, PerformGroupEnums performGroup, String topOrgId) {
        return getOrgTree(activityInstId, nextActivityDefId, performGroup, topOrgId);
    }


    private TreeListResultModel<List<PerformOrgTree>> getOrgTree(String activityInstId, String nextActivityDefId, PerformGroupEnums performGroup, String topOrgId) {
        TreeListResultModel<List<PerformOrgTree>> orgTreeResultModule = new TreeListResultModel<>();
        List<PerformOrgTree> activityTrees = new ArrayList<>();
        ActivityDef activityDef = null;
        try {
            activityDef = this.getClient().getActivityDef(nextActivityDefId);
            ActivityDefRight activityDefRight = activityDef.getRightAttribute();
            List<Person> personList = new ArrayList<Person>();
            Org topOrg = this.getTopOrg(topOrgId);
            switch (performGroup) {
                case readers:
                    personList = activityDefRight.getReaderPersons();
                    break;
                case performs:
                    personList = activityDefRight.getPerFormPersons();
                    break;
                case insteadSigns:
                    personList = activityDefRight.getInsteadSignPersons();
                    break;
            }
            PerformOrgTree orgTree = new PerformOrgTree(topOrg, personList, this.getAllOrg(personList, topOrgId), true, null);
            activityTrees.add(orgTree);
            orgTreeResultModule.setData(activityTrees);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return orgTreeResultModule;

    }


    private List<Org> getAllOrg(List<Person> personList, String topOrgId) {
        Map orgMap = new HashMap();
        List<Org> allOrgs = new ArrayList<Org>();
        for (int i = 0; i < personList.size(); i++) {
            Person perosn = (Person) personList.get(i);
            List<Org> orgs = perosn.getOrgList();
            if (orgs != null) {
                for (Org org : orgs) {
                    if (!orgMap.containsKey(org.getOrgId())) {
                        addOrg(orgMap, org, topOrgId);
                    }
                }
            }
        }
        allOrgs.addAll(orgMap.values());
        return allOrgs;
    }

    @JSONField(serialize = false)
    private Org getTopOrg(String topOrgId) throws OrgNotFoundException {


        Org topOrg = OrgManagerFactory.getOrgManager().getOrgByID(topOrgId);

        return topOrg;

    }

    /**
     * @param map
     * @param org
     */
    private Map<String, Org> addOrg(Map<String, Org> map, Org org, String topOrgId) {
        if (org != null) {
            map.put(org.getOrgId(), org);
            Org parent = org.getParent();

            if (parent != null) {
                if (topOrgId != null && org.getOrgId().equals(topOrgId)) {

                    map.put(parent.getOrgId(), parent);
                } else {
                    if (!map.containsKey(parent.getOrgId())) {
                        addOrg(map, parent, topOrgId);
                    }
                }

            }

        }
        return map;

    }

    /**
     * @return
     */
    @JSONField(serialize = false)
    public WorkflowClientService getClient() {
        WorkflowClientService client = ((WorkflowClientService) EsbUtil.parExpression("$BPMC"));
        return client;
    }
}
